#include <linux/init.h>
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/device.h>
#include <linux/device/class.h>
#include <linux/fs.h>
#include <linux/device/class.h>
#include <linux/device.h>

#include "wd_drv.h"

struct class *pCls;
int major;
struct i2c_client *client;

int get_value(char reg){
    int ret;
    unsigned short value;
    struct i2c_msg msg[2]={
        [0]={
            .addr = client->addr,
            .flags = 0,
            .len = 1,
            .buf = &reg,    
        },
        [1]={
            .addr = client->addr,
            .flags = 1,
            .len = 2,
            .buf = (char *)&value,
        }
    };
    //
    ret = i2c_transfer(client->adapter, msg, 2);
    if(ret != ARRAY_SIZE(msg)){
        printk("i2c_transfer failed!\n");
        return -1;
    }
    return value;
}

long file_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
    int value;
    if(cmd == WD_GET){//测温度
        value = get_value(0xE3);
    }else if(cmd == SD_GET){//测湿度
        value = get_value(0xE5);
    }else{
        return -1;
    }
    if(copy_to_user((int *)arg, &value, sizeof(int))){
        return -1;
    }
    printk("ioctl success! value=[%d][%#X]\n", value, value);
    return 0;
}

struct file_operations fops = {
    .unlocked_ioctl = file_ioctl,
};

int wd_probe(struct i2c_client *client_p, const struct i2c_device_id *id)
{
    struct device *pDev;
    client = client_p;
    //
    printk("wd_probe!\n");
    //
    major = register_chrdev(0, "wd_drv", &fops);
    if (major<0)
    {
        printk("register_chrdev failed!\n");
        goto ERR1;
    }
    printk("registr_chrdev success!\n");
    //
    pCls = class_create(THIS_MODULE, "wd_drv");
    if (IS_ERR(pCls))
    {
        printk("class_create failed!\n");
        goto ERR2;
    }
    printk("class_create success!\n");
    //
    pDev = device_create(pCls, NULL, MKDEV(major,0), NULL, "mywd");
    if(IS_ERR(pDev)){
        printk("device_create failed!\n");
        goto ERR3;
    }
    printk("device_create success!\n");
    //
    

    printk("设备驱动注册完成!\n");
    return 0;

ERR3:
    class_destroy(pCls);
ERR2:
    unregister_chrdev(major, "wd_drv");
ERR1:
    return -1;
}

int wd_remove(struct i2c_client *client)
{
    printk("wd_remove!\n");
    device_destroy(pCls, MKDEV(major, 0));
    class_destroy(pCls);
    unregister_chrdev(major, "wd_drv");
    return 0;
}

const struct of_device_id of_match_table[] = {
    {.compatible = "zr,mywd"}, {}};

struct i2c_driver wd_drv = {
    .driver = {
        .name = "mywd",
        .of_match_table = of_match_table},
    .probe = wd_probe,
    .remove = wd_remove,
};

module_i2c_driver(wd_drv);
MODULE_LICENSE("GPL");